#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

void DFT(Mat &frame)
{
    Mat srcimage = frame;
    if (!srcimage.data)
    {
        printf("falsch!\n");
    }
    //imshow("原始图像", srcimage);

    //2,将输入尺寸扩大到最佳尺寸，边界用0填充
    int m = getOptimalDFTSize(srcimage.rows);
    int n = getOptimalDFTSize(srcimage.cols);
    Mat padded;
    copyMakeBorder(srcimage, padded, 0, m - srcimage.rows, 0, n - srcimage.cols, BORDER_CONSTANT, Scalar::all(0)); //初始化元素为0，扩充

    //3,傅里叶变化结果（实部虚部）分配储存空间
    //将plannes数组组合合并成一个多通道的数组complexI
    Mat plannes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; //新建一个两页的array，其中第一页用扩展后的图像初始化，第二页初始化为0
    Mat complexI;
    merge(plannes, 2, complexI);

    //4，进行就地傅里叶变换
    dft(complexI, complexI);

    //5，将复数转化为幅值，即log（1+sqrt（Re(DFT(I)^2+Im(DFT(I))）^2）
    split(complexI, plannes); //多通道分离为几个单通道数组,plannes[0]=Re(DFT(I),plannes[1]=Im(DFT(I)
    magnitude(plannes[0], plannes[1], plannes[0]);
    Mat magnitudeImage = plannes[0];

    //6，进行对数尺度（logarithmic scale）缩放
    magnitudeImage += Scalar::all(1);    //等效于  magnitudeImage = magnitudeImage + Scalar::all(1);
    log(magnitudeImage, magnitudeImage); //求自然对数

    //7，剪切和重新分布幅度图象限
    //若有奇数行/列，进行频谱裁剪
    magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
    //重新排列傅里叶图像的象限，是的原点位于图像中心
    int cx = magnitudeImage.cols / 2;
    int cy = magnitudeImage.rows / 2;
    Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); //Roi区域的左上，右上，左下，右下
    Mat q2(magnitudeImage, Rect(0, cy, cx, cy));
    Mat q3(magnitudeImage, Rect(cx, cy, cx, cy));
    Mat q1(magnitudeImage, Rect(cx, 0, cx, cy));

    //交换象限（左上和右下）
    Mat tmp;
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);

    //交换象限（右上与左下）
    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);

    //8，归一化，用0到1间的浮点数将矩阵变化为可视的图像格式
    normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);

    imshow("Articulation", magnitudeImage);

    int a, b, sum;
    a = magnitudeImage.rows;
    b = magnitudeImage.cols;
    sum = a * b;
    //cout << sum << endl;
    int c = 0;
    //双重循环，遍历所有的像素值
    for (int i = 0; i < a; i++) //行循环
    {
        uchar *data = magnitudeImage.ptr<uchar>(i); //获取第i行的首地址
        for (int j = 0; j < b; j++)                 //列循环
        {
            if ((int)data[j] > 230)
            {
                c++;
            }
        }
    }
    static int framenum = 0;
    //cout << "C =" << c << endl;
    double Rate = (double)c / sum;
    //cout << Rate << endl;
    stringstream meanValueStream;
    string meanValueString;
    meanValueStream << Rate;
    meanValueStream >> meanValueString;
    meanValueString = "tiaowen" + meanValueString;
    if (Rate > 0.3)
    {
        framenum++;
        printf("条纹异常\n");
        putText(magnitudeImage, meanValueString, Point(100, 50), CV_FONT_HERSHEY_COMPLEX, 0.8, Scalar(255, 255, 25), 2);
    }
}

int main() //tiaowen
{
    //打开视频文件：其实就是建立一个VideoCapture结构
    VideoCapture capture("/Users/lukeskywalker/Desktop/Jitter.mov");
    //检测是否正常打开:成功打开时，isOpened返回ture
    if (!capture.isOpened())
        cout << "fail to open!" << endl;
    //定义一个用来控制读取视频循环结束的变量
    bool stop = false;
    //承载每一帧的图像
    Mat frame;
    Mat gray;
    Mat tempframe;
    Mat CannyImg;
    Mat image_hsv;
    Mat image_dft;
    int framenum = 0;
    //显示每一帧的窗口

    while (!stop)
    {
        //读取下一帧
        if (!capture.isOpened())
        {
            cout << "读取视频失败" << endl;
            return -1;
        }

        //获取整个帧数
        long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);
        //cout << "整个视频共" << totalFrameNumber << "帧" << endl;()
        capture >> frame;
        tempframe = frame;
        framenum++;
        if (framenum == 1)
        {
            cvtColor(tempframe, gray, CV_BGR2GRAY);
            cvtColor(tempframe, image_hsv, CV_BGR2HSV);
            //dft(image_hsv, image_dft);
        }
        if (framenum >= 2)
        {
            cvtColor(tempframe, gray, CV_BGR2GRAY); //转化为单通道灰度图，此时currentFrame已经存了tempFrame的内容
            cvtColor(tempframe, image_hsv, CV_BGR2HSV);

            //dft(image_hsv, image_dft);

            //显示图像
            //imshow("camera", tempframe);
            //imshow("moving area", gray);
        }
        vector<Mat> hsvChannels;
        split(image_hsv, hsvChannels);
        //dft(hsvChannels[0], image_dft);

        if (!(framenum % 1))
        {
            printf("f:%d\n", framenum);
            //***suanfa;
        }

        DFT(hsvChannels[0]);

        //imshow("result", hsvChannels[0]);

        //imshow("after filter", image_dft);
        int c = waitKey(10);
        //按下ESC或者到达指定的结束帧后退出读取视频
        if ((char)c == 27)
        {
            stop = true;
        }
        //按下按键后会停留在当前帧，等待下一次按键
        if (c >= 0)
        {
            waitKey(0);
        }
    }
    //关闭视频文件
    capture.release();
    waitKey(0);
    return 0;
}
